/****************************************************************************
 * ifu_tb.v
 ****************************************************************************/

`include "../general/xchecker.v"
`include "../general/dffs.v"
`include "../sram/sram.v"
`include "../risc_t16_i_core/ifu.v"

/**
 * Module: ifu_tb
 * 
 * ifu模块的测试文件
 */
 
`timescale 1ns / 10ps

module ifu_tb;

    parameter   DATA_WIDTH  =   16;
    parameter   ADDR_WIDTH  =   12;
	parameter   DELAY_TIME  =   1;
	parameter 	INIT_FILE   = 	"hello_code.hex";
	parameter 	PERI 		= 	10;
	
    reg                             rst;                    // 系统复位信号，同步复位，高电平有效
    reg                             clk;                    // 系统工作时钟

    // 上层系统向ifu发送启动工作的信号接口，icb标准信号，ifu为从设备接收命令
    reg                             sys2ifu_cmd_start;      // 系统工作启动信号，高电平有效
    reg                             sys2ifu_cmd_req;
    wire                            sys2ifu_cmd_ack;

    // 程序存储器相关接口，采用icb标准信号接口，ifu作为主设备读写mem
    wire                            ifu2mem_cmd_wr;         // 写读命令，高电平写，低电平读
    wire                            ifu2mem_cmd_req;      
    reg                             ifu2mem_cmd_ack;      
    reg                             ifu2mem_rsp_req;
    wire                            ifu2mem_rsp_ack;
    reg                             ifu2mem_rsp_err;
    wire       [ADDR_WIDTH-1 : 0]   ifu2mem_addr;           // 地址
    wire       [DATA_WIDTH-1 : 0]   ifu2mem_dout;           // 写数据
    wire       [DATA_WIDTH-1 : 0]   ifu2mem_din;            // 读数据

    // 后端译码和执行单元相关接口，此时取指模块作为主设备向译码执行单元写数据
    wire                            ifu2deu_cmd_req;      // 发送给后端译码和执行单元的命令状态信号，高电平有效
    reg                             ifu2deu_cmd_ack;      // 后端译码执行单元反馈的命令接受状态信号，高电平有效
	reg                             ifu2deu_rsp_done;       // deu向ifu发送的程序执行完毕信号，HLT指令执行完
	reg								ifu2deu_rsp_taken;
    wire                            ifu2deu_instr_ctrl;     // 控制指令
    wire                            ifu2deu_instr_jmp;      // 无条件跳转指令
    wire                            ifu2deu_instr_bjp;      // 条件跳转指令
    wire                            ifu2deu_instr_short;    // 短周期指令
    wire                            ifu2deu_instr_long;     // 长周期指令
    wire       [DATA_WIDTH-3 : 0]   ifu2deu_instr_res;      // 指令除了op1剩余的部分
    wire       [ADDR_WIDTH-1 : 0]   ifu2deu_pc;             // 当前指令的pc值

	
	ifu #(	
    	.DATA_WIDTH(DATA_WIDTH),
    	.ADDR_WIDTH(ADDR_WIDTH),
    	.DELAY_TIME(DELAY_TIME)
    )
	ifu_inst (
    	.rst(rst),                    // 系统复位信号，同步复位，高电平有效
    	.clk(clk),                    // 系统工作时钟

    	// 上层系统向ifu发送启动工作的信号接口，icb标准信号，ifu为从设备接收命令
    	.sys2ifu_cmd_start(sys2ifu_cmd_start),      // 系统工作启动信号，高电平有效
    	.sys2ifu_cmd_req(sys2ifu_cmd_req),
    	.sys2ifu_cmd_ack(sys2ifu_cmd_ack),

		.ifu2deu_rsp_done(ifu2deu_rsp_done),
		.ifu2deu_rsp_taken(ifu2deu_rsp_taken),
    	// 程序存储器相关接口，采用icb标准信号接口，ifu作为主设备读写mem
    	.ifu2mem_cmd_wr(ifu2mem_cmd_wr),         // 写读命令，高电平写，低电平读
    	.ifu2mem_cmd_req(ifu2mem_cmd_req),      
    	.ifu2mem_cmd_ack(ifu2mem_cmd_ack),      
    	.ifu2mem_rsp_req(ifu2mem_rsp_req),
    	.ifu2mem_rsp_ack(ifu2mem_rsp_ack),
    	.ifu2mem_rsp_err(ifu2mem_rsp_err),
    	.ifu2mem_addr(ifu2mem_addr),           // 地址
    	.ifu2mem_dout(ifu2mem_dout),           // 写数据
    	.ifu2mem_din(ifu2mem_din),             // 读数据

    	// 后端译码和执行单元相关接口，此时取指模块作为主设备向译码执行单元写数据
    	.ifu2deu_cmd_req(ifu2deu_cmd_req),      // 发送给后端译码和执行单元的命令状态信号，高电平有效
    	.ifu2deu_cmd_ack(ifu2deu_cmd_ack),      // 后端译码执行单元反馈的命令接受状态信号，高电平有效
    	.ifu2deu_instr_ctrl(ifu2deu_instr_ctrl),       	// 控制指令
		.ifu2deu_instr_jmp(ifu2deu_instr_jmp),
    	.ifu2deu_instr_bjp(ifu2deu_instr_bjp),        	// 条件跳转指令
    	.ifu2deu_instr_short(ifu2deu_instr_short),      // 短周期指令
    	.ifu2deu_instr_long(ifu2deu_instr_long),       	// 长周期指令
    	.ifu2deu_instr_res(ifu2deu_instr_res),      // 指令除了op1剩余的部分
    	.ifu2deu_pc(ifu2deu_pc)             		// 当前指令的pc值
    );


	sram #(
		.ADDR_WIDTH(ADDR_WIDTH),
		.DATA_WIDTH(DATA_WIDTH),
		.INIT_FILE(INIT_FILE),
		.DELAY_TIME(DELAY_TIME)
	)
	sram_inst (
		.cs(ifu2mem_cmd_req),
		.wr(ifu2mem_cmd_wr),
		.addr(ifu2mem_addr),
		.din(ifu2mem_dout),
		.dout(ifu2mem_din)
	);



	always #(PERI/2) clk = ~clk;
	
	initial
	begin
		$dumpfile("ifu_tb.vcd");
        $dumpvars(0, ifu_tb);

		rst 		= 1'b0;
		clk			= 1'b0;
		sys2ifu_cmd_start = 0;
		sys2ifu_cmd_req = 0;

		ifu2deu_rsp_taken = 0;
		ifu2deu_cmd_ack = 1;


		// 系统复位
		#(PERI)
		#6
		rst 	= 1'b1;

		// 复位结束
		#(PERI*2)
		rst		= 1'b0;

		// 启动取指
		#PERI
		sys2ifu_cmd_start 	= 1'b1;
		sys2ifu_cmd_req   = 1'b1;

		#PERI
		sys2ifu_cmd_start 	= 1'b0;
		sys2ifu_cmd_req   = 1'b0;

		// 模拟正常工作50个周期，然后置位工作完成done信号
		#(PERI*50)
		ifu2deu_rsp_done  	= 1'b1;

		#PERI
		ifu2deu_rsp_done	= 1'b0;

		#(PERI*2)

		#PERI $finish;

	end

	// always ifu2deu_cmd_ack = #DELAY_TIME ((~ifu2deu_instr_bjp) | op_bjp_finish) & (~ifu2deu_instr_long | op_long_finish);
	// always ifu2deu_rsp_taken = #DELAY_TIME ifu2deu_instr_bjp;
	// reg op_bjp_finish = 0;
	// reg op_long_finish = 0;
	// always @(posedge clk)
	// begin
	// 	#DELAY_TIME op_bjp_finish = ifu2deu_instr_bjp;
	// end

	// always @(posedge clk)
	// begin
	// 	#(PERI + DELAY_TIME) op_long_finish = ifu2deu_instr_long;
	// end
	
endmodule


